package com.zycfc.zsf.boot.core.zsfvalue;

import org.springframework.beans.factory.config.*;
import com.google.common.collect.*;
import com.google.common.base.*;
import java.util.*;
import org.springframework.util.*;

public class PlaceholderHelper
{
    private static final String PLACEHOLDER_PREFIX = "${";
    private static final String PLACEHOLDER_SUFFIX = "}";
    private static final String VALUE_SEPARATOR = ":";
    private static final String SIMPLE_PLACEHOLDER_PREFIX = "{";
    private static final String EXPRESSION_PREFIX = "#{";
    private static final String EXPRESSION_SUFFIX = "}";
    
    public Object resolvePropertyValue(final ConfigurableBeanFactory beanFactory, final String beanName, final String placeholder) {
        final String strVal = beanFactory.resolveEmbeddedValue(placeholder);
        final BeanDefinition bd = beanFactory.containsBean(beanName) ? beanFactory.getMergedBeanDefinition(beanName) : null;
        return this.evaluateBeanDefinitionString(beanFactory, strVal, bd);
    }
    
    private Object evaluateBeanDefinitionString(final ConfigurableBeanFactory beanFactory, final String value, final BeanDefinition beanDefinition) {
        if (beanFactory.getBeanExpressionResolver() == null) {
            return value;
        }
        final Scope scope = (beanDefinition != null) ? beanFactory.getRegisteredScope(beanDefinition.getScope()) : null;
        return beanFactory.getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(beanFactory, scope));
    }
    
    public ZsfKeys extractPlaceholderKeys(final String propertyString) {
        final ZsfKeys keys = new ZsfKeys();
        final Set<String> placeholderKeys = (Set<String>)Sets.newHashSet();
        if (!this.isNormalizedPlaceholder(propertyString) && !this.isExpressionWithPlaceholder(propertyString)) {
            keys.getKeys().add(propertyString);
            return keys;
        }
        final Stack<String> stack = new Stack<String>();
        stack.push(propertyString);
        while (!stack.isEmpty()) {
            final String strVal = stack.pop();
            final int startIndex = strVal.indexOf("${");
            if (startIndex == -1) {
                placeholderKeys.add(strVal);
                keys.getKeys().addAll(placeholderKeys);
            }
            else {
                final int endIndex = this.findPlaceholderEndIndex(strVal, startIndex);
                if (endIndex == -1) {
                    continue;
                }
                final String placeholderCandidate = strVal.substring(startIndex + "${".length(), endIndex);
                if (placeholderCandidate.startsWith("${")) {
                    stack.push(placeholderCandidate);
                }
                else {
                    final int separatorIndex = placeholderCandidate.indexOf(":");
                    if (separatorIndex == -1) {
                        stack.push(placeholderCandidate);
                    }
                    else {
                        stack.push(placeholderCandidate.substring(0, separatorIndex));
                        final String defaultValue = placeholderCandidate.substring(separatorIndex + ":".length());
                        final String defaultValuePart = this.normalizeToPlaceholder(defaultValue);
                        if (!Strings.isNullOrEmpty(defaultValuePart)) {
                            stack.push(defaultValuePart);
                        }
                        else {
                            keys.setDefaultValue(defaultValue);
                        }
                    }
                }
                if (endIndex + "}".length() >= strVal.length() - 1) {
                    continue;
                }
                final String remainingPart = this.normalizeToPlaceholder(strVal.substring(endIndex + "}".length()));
                if (Strings.isNullOrEmpty(remainingPart)) {
                    continue;
                }
                stack.push(remainingPart);
            }
        }
        return keys;
    }
    
    private boolean isNormalizedPlaceholder(final String propertyString) {
        return propertyString.startsWith("${") && propertyString.endsWith("}");
    }
    
    private boolean isExpressionWithPlaceholder(final String propertyString) {
        return propertyString.startsWith("#{") && propertyString.endsWith("}") && propertyString.contains("${");
    }
    
    private String normalizeToPlaceholder(final String strVal) {
        final int startIndex = strVal.indexOf("${");
        if (startIndex == -1) {
            return null;
        }
        final int endIndex = strVal.lastIndexOf("}");
        if (endIndex == -1) {
            return null;
        }
        return strVal.substring(startIndex, endIndex + "}".length());
    }
    
    private int findPlaceholderEndIndex(final CharSequence buf, final int startIndex) {
        int index = startIndex + "${".length();
        int withinNestedPlaceholder = 0;
        while (index < buf.length()) {
            if (StringUtils.substringMatch(buf, index, (CharSequence)"}")) {
                if (withinNestedPlaceholder <= 0) {
                    return index;
                }
                --withinNestedPlaceholder;
                index += "}".length();
            }
            else if (StringUtils.substringMatch(buf, index, (CharSequence)"{")) {
                ++withinNestedPlaceholder;
                index += "{".length();
            }
            else {
                ++index;
            }
        }
        return -1;
    }
    
    public static void main(final String[] args) {
        final String a = "${spring.util.timeout.sec:${SPRING_UTIL_TIMEOUT_SEC:1}}";
        final PlaceholderHelper p = new PlaceholderHelper();
        final ZsfKeys list = p.extractPlaceholderKeys(a);
        System.out.println(list.getKeys().toString() + "--" + list.getDefaultValue());
    }
}
